package com.jinsp.router_api;

import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.Fragment;
import android.text.TextUtils;

import com.jinsp.router_annotation.bean.RouterBean;

import java.util.Map;

/**
 * Created by luoshuai on 12/13/21
 * <p>
 * 路由API，实现参数以及路由跳转功能
 */
public class RouterApi {

    private static final String ROUTER_FILE_PACKAGE_NAME = "com.jinsp.componentrouter."; //生成文件的固定包名
    private static final String INTENT_PARAMETER_CLASS_NAME_PREFIX = "Router_IntentParameter_"; //Intent参数文件名前缀
    private static final RouterLruCache<String, IIntentParameter> PARAMETER_LRU_CACHE = new RouterLruCache<>(16);
    private static final String GROUP_CLASS_NAME_PREFIX = "Router_Group_";    //组文件名前缀
    private static final RouterLruCache<String, IRouterGroup> ROUTER_GROUP_LRU_CACHE = new RouterLruCache<>(16);
    private static final RouterLruCache<String, IRouterPath> ROUTER_PATH_LRU_CACHE = new RouterLruCache<>(16);
    private static String groupName, pathName;     //路由组名以及类路径
    public static final int START_NOT_FOR_RESULT = -1;  //非FOR RESULT跳转

    /**
     * 绑定Activity获取Intent参数
     *
     * @param activity Activity对象
     */
    public static void bindActivityIntentParameter(Activity activity) {
        if (activity != null) {
            Class<?> clazz = activity.getClass();
            String className = clazz.getSimpleName();
            String canonicalName = clazz.getCanonicalName();
            String packageName = canonicalName.substring(0, canonicalName.lastIndexOf("."));
            try {
                String fullClassName = packageName + "."
                        + INTENT_PARAMETER_CLASS_NAME_PREFIX + className;
                IIntentParameter intentParameter = PARAMETER_LRU_CACHE.get(fullClassName);
                if (intentParameter == null) {
                    Class<?> targetClass = Class.forName(fullClassName);
                    if (targetClass != null) {
                        intentParameter = (IIntentParameter) targetClass.newInstance();
                    } else {
                        throw new ClassNotFoundException(fullClassName + "can not found");
                    }
                    PARAMETER_LRU_CACHE.put(fullClassName, intentParameter);
                }
                if (intentParameter != null) {
                    intentParameter.getParameter(activity);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 绑定Service获取Intent参数
     *
     * @param service 服务
     * @param intent  onStartCommand(Intent intent）中的intent
     */
    public static void bindServiceIntentParameter(Service service, Intent intent) {
        if (service != null && intent != null) {
            Class<?> clazz = service.getClass();
            String className = clazz.getSimpleName();
            String packageName = service.getPackageName();
            try {
                String fullClassName = packageName + "."
                        + INTENT_PARAMETER_CLASS_NAME_PREFIX + className;
                IIntentParameter intentParameter = PARAMETER_LRU_CACHE.get(fullClassName);
                if (intentParameter == null) {
                    Class<?> targetClass = Class.forName(fullClassName);
                    if (targetClass != null) {
                        intentParameter = (IIntentParameter) targetClass.newInstance();
                    } else {
                        throw new ClassNotFoundException(fullClassName + "can not found");
                    }
                    PARAMETER_LRU_CACHE.put(fullClassName, intentParameter);
                }
                if (intentParameter != null) {
                    intentParameter.getParameter(service, intent);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 目标路径
     *
     * @param groupName 目标组名
     * @param pathName  目标路径
     * @return 参数配置
     */
    public static ParameterManager target(String groupName, String pathName) {
        //校验组名以及路径名
        if (TextUtils.isEmpty(pathName)) {
            throw new NullPointerException("路径不能为空");
        }
        if (pathName.startsWith("/")) {
            pathName = pathName.substring(1);
        }
        char firstChar = pathName.charAt(0);
        //首字符必须是字母
        if (!Character.isLowerCase(firstChar) && !Character.isUpperCase(firstChar)) {
            throw new RuntimeException("pathName must lower or upper case");
        }
        //pathName必须为：xxx/xxx
        String[] split = pathName.split("/");
        //第一个组名必须为字母
        if (split.length < 2) {
            throw new IllegalArgumentException("路径格式必须为xxx/xxx");
        }
        String firstPathName = split[0];
        if (!firstPathName.matches("[a-zA-Z]+")) {
            throw new IllegalArgumentException("路径必须为全字母");
        }
        //没有组名的情况，使用path中的组名
        if (TextUtils.isEmpty(groupName)) {
            groupName = firstPathName;
        } else {
            if (!groupName.matches("[a-zA-Z]+")) {
                throw new IllegalArgumentException("组名必须为全字母");
            }
        }
        RouterApi.groupName = groupName;
        RouterApi.pathName = pathName;
        return new ParameterManager();
    }

    /**
     * 导航到新的Activity，支持ForResult跳转
     *
     * @param context          上下文
     * @param parameterManager 跳转参数
     * @param requestCode      请求码，不需要参数跳转传递-1，此外当context不是activity时只能startActivity
     */
    protected static void navigationActivity(Context context, ParameterManager parameterManager,
                                             int requestCode) {
        RouterBean routerBean = findTargetRouterBean();
        RouterBean.RouterType routerBeanType = routerBean.getType();
        if (routerBeanType == RouterBean.RouterType.ACTIVITY) {
            //判断是否为Activity启动
            Intent intent = new Intent(context, routerBean.getTargetClass());
            if (!(context instanceof Activity)) {
                requestCode = START_NOT_FOR_RESULT;
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            if (parameterManager.getBundle() != null) {
                intent.putExtras(parameterManager.getBundle());
            }
            if (requestCode != START_NOT_FOR_RESULT) {
                ((Activity) context).startActivityForResult(intent, requestCode);
            } else {
                context.startActivity(intent);
            }
            //查看是否使用转场动画
            if (context instanceof Activity && parameterManager.getEnterAnim() != 0
                    && parameterManager.getExitAnim() != 0) {
                ((Activity) context).overridePendingTransition(parameterManager.getEnterAnim(),
                        parameterManager.getExitAnim());
            }
        } else {
            throw new RuntimeException("target is not an activity");
        }
    }

    /**
     * 导航到新的Activity，支持ForResult跳转，Fragment内使用
     *
     * @param fragment         v4Fragment实例
     * @param parameterManager 跳转参数
     * @param requestCode      请求码，不需要参数跳转传递-1
     */
    public static void navigationActivity(Fragment fragment, ParameterManager parameterManager,
                                          int requestCode) {
        RouterBean routerBean = findTargetRouterBean();
        RouterBean.RouterType routerBeanType = routerBean.getType();
        if (routerBeanType == RouterBean.RouterType.ACTIVITY) {
            Intent intent = new Intent(fragment.getContext(), routerBean.getTargetClass());
            if (parameterManager.getBundle() != null) {
                intent.putExtras(parameterManager.getBundle());
            }
            if (requestCode == START_NOT_FOR_RESULT) {
                fragment.startActivity(intent);
            } else {
                fragment.startActivityForResult(intent, requestCode);
            }
            if (parameterManager.getEnterAnim() != 0 && parameterManager.getExitAnim() != 0) {
                fragment.getActivity().overridePendingTransition(parameterManager.getEnterAnim(),
                        parameterManager.getExitAnim());
            }
        } else {
            throw new RuntimeException("target is not an activity");
        }
    }

    /**
     * 导航Service
     *
     * @param context          上下文
     * @param parameterManager 跳转参数
     * @param isStop           是否为关闭服务
     */
    protected static void navigationService(Context context, ParameterManager parameterManager,
                                            boolean isStop) {
        RouterBean routerBean = findTargetRouterBean();
        RouterBean.RouterType routerBeanType = routerBean.getType();
        if (routerBeanType == RouterBean.RouterType.SERVICE) {
            Intent intent = new Intent(context, routerBean.getTargetClass());
            if (parameterManager.getBundle() != null) {
                intent.putExtras(parameterManager.getBundle());
            }
            if (isStop) {
                //关闭服务
                context.stopService(intent);
            } else {
                //启动服务
                context.startService(intent);
            }
        } else {
            throw new RuntimeException("target is not a service");
        }
    }

    /**
     * 导航到新的Fragment
     *
     * @param parameterManager 跳转参数
     * @return v4包下Fragment
     */
    protected static Fragment navigationFragment(ParameterManager parameterManager) {
        RouterBean routerBean = findTargetRouterBean();
        RouterBean.RouterType routerBeanType = routerBean.getType();
        if (routerBeanType == RouterBean.RouterType.V4FRAGMENT) {
            //创建fragment
            try {
                Object instance = routerBean.getTargetClass().newInstance();
                if (instance instanceof Fragment) {
                    ((Fragment) instance).setArguments(parameterManager.getBundle());
                    return (Fragment) instance;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            throw new RuntimeException("target is not a v4-fragment");
        }
        return null;
    }

    /**
     * 查询路由表目标信息
     *
     * @return 路由信息
     */
    private static RouterBean findTargetRouterBean() {
        if (TextUtils.isEmpty(groupName) || TextUtils.isEmpty(pathName)) {
            throw new NullPointerException("groupName or pathName can not empty");
        }
        RouterBean routerBean = null;
        //寻找对应组文件
        IRouterGroup routerGroup = ROUTER_GROUP_LRU_CACHE.get(groupName);
        if (routerGroup == null) {
            try {
                String fullGroupClassName = ROUTER_FILE_PACKAGE_NAME + GROUP_CLASS_NAME_PREFIX + groupName;
                Class<?> groupClass = Class.forName(fullGroupClassName);
                if (groupClass != null) {
                    routerGroup = (IRouterGroup) groupClass.newInstance();
                } else {
                    throw new ClassNotFoundException(fullGroupClassName + "can not found");
                }
                ROUTER_GROUP_LRU_CACHE.put(groupName, routerGroup);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (routerGroup != null) {
            Map<String, Class<? extends IRouterPath>> groupMap = routerGroup.getGroupMap();
            if (groupMap == null) {
                throw new NullPointerException("router error");
            }
            Class<? extends IRouterPath> pathClass = groupMap.get(groupName);
            if (pathClass == null) {
                throw new NullPointerException("router error");
            }
            //查找组中的路径
            IRouterPath routerPath = ROUTER_PATH_LRU_CACHE.get(pathName);
            if (routerPath == null) {
                try {
                    routerPath = pathClass.newInstance();
                    ROUTER_PATH_LRU_CACHE.put(pathName, routerPath);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            assert routerPath != null;
            Map<String, RouterBean> pathMap = routerPath.getPathMap();
            if (pathMap == null) {
                throw new NullPointerException("router error");
            }
            routerBean = pathMap.get(pathName);
        }
        if (routerBean == null) {
            throw new NullPointerException("router error");
        }
        return routerBean;
    }
}
